package com.xuecheng.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.api.learning.model.dto.CourseRecordDTO;
import com.xuecheng.api.media.model.vo.ResourceUrlModel;
import com.xuecheng.api.search.model.dto.CoursePubIndexDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.learning.agent.MediaApiAgent;
import com.xuecheng.learning.agent.SearchApiAgent;
import com.xuecheng.learning.common.constant.LearningErrorCode;
import com.xuecheng.learning.convert.CourseRecordConvert;
import com.xuecheng.learning.entity.CourseRecord;
import com.xuecheng.learning.mapper.CourseRecordMapper;
import com.xuecheng.learning.service.CourseRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 选课记录 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseRecordServiceImpl extends ServiceImpl<CourseRecordMapper, CourseRecord> implements CourseRecordService {
    @Autowired
    private SearchApiAgent searchApiAgent;
    @Autowired
    private MediaApiAgent mediaApiAgent;

    /**
     * 根据课程发布信息id获取课程记录
     *
     * @param coursePubId 课程发布信息id
     * @return 获取课程记录
     * ===业务分析===
     * 1.判断关键数据
     * coursePubId,userId
     * <p>
     * 2.判断数据查询课程学习记录数据
     * 如果有数据,进行po转dto
     * 如果无数据,返回一个空的数据对象
     */
    @Override
    public CourseRecordDTO getRecordByCoursePubId(Long coursePubId, String userName) {
        //1.判断关键数据
        if (ObjectUtils.isEmpty(coursePubId) || StringUtil.isBlank(userName)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //2.判断数据查询课程学习记录数据
        LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);
        queryWrapper.eq(CourseRecord::getUserName, userName);

        CourseRecord courseRecord = this.getOne(queryWrapper);

        if (ObjectUtils.isEmpty(courseRecord)) {
            return new CourseRecordDTO();
        }
        CourseRecordDTO courseRecordDTO = CourseRecordConvert.INSTANCE.entity2dto(courseRecord);
        return courseRecordDTO;
    }

    /**
     * 创建或者修改学习记录
     *
     * @param dto 课程记录
     *            业务分析
     *            1.判断关键数据
     *            username,coursePubId
     *            2.判断业务数据
     *            获取课程发布数据
     *            判断课程是否收费
     *            3.根据username,coursePubId获取课程学习计划
     *            如果有==>修改
     *            修改学习进度==>teachplanId
     *            如果没有==>新增
     *            4.将最新的课程记录返回
     */
    @Override
    @Transactional
    public CourseRecordDTO createOrModifyRecord(CourseRecordDTO dto) {
        //1.判断关键数据
        if (ObjectUtils.isEmpty(dto)) {
            ExceptionCast.cast(LearningErrorCode.E_202202);
        }
        String userName = dto.getUserName();
        Long coursePubId = dto.getCoursePubId();
        if (StringUtil.isBlank(userName) || ObjectUtils.isEmpty(coursePubId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.判断业务数据
        //判断课程发布信息
        RestResponse<CoursePubIndexDTO> response = this.searchApiAgent.getCoursePubIndexById4s(coursePubId);
        CoursePubIndexDTO coursePubIndexDTO = response.getResult();
        if (!response.isSuccessful() || ObjectUtils.isEmpty(coursePubIndexDTO)) {
            ExceptionCast.cast(LearningErrorCode.E_202202);
        }
        //判断是否是收费课程
        if (CourseChargeEnum.CHARGE_NO.getCode().equals(coursePubIndexDTO.getCharge())) {
            ExceptionCast.cast(CommonErrorCode.E_100107);
        }
        //3.根据username,coursePubId获取课程学习计划
        LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseRecord::getUserName, userName);
        queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);
        CourseRecord record = this.getOne(queryWrapper);
        //如果有==>修改
        //   修改学习进度==>teachplanId
        //   如果没有==>新增
        CourseRecordDTO courseRecordDTO = new CourseRecordDTO();
        if (ObjectUtils.isEmpty(record)) {
            courseRecordDTO = create(dto, coursePubIndexDTO);
        } else {
            dto.setCourseRecordId(record.getId());
            courseRecordDTO = modify(dto);
        }
        //4.将最新的课程记录返回
        return courseRecordDTO;
    }

    private CourseRecordDTO modify(CourseRecordDTO dto) {
        CourseRecord record = CourseRecordConvert.INSTANCE.dto2entity(dto);
        LambdaUpdateWrapper<CourseRecord> updateWrapper = new LambdaUpdateWrapper<>();

        //设置修改时间
        updateWrapper.set(CourseRecord::getChangeDate, LocalDateTime.now());
        //设置正在学习的课程计划章节Id
        updateWrapper.set(CourseRecord::getTeachplanId, dto.getTeachplanId());
        //正在学习的课程计划章节名称
        updateWrapper.set(CourseRecord::getTeachplanName, dto.getTeachplanName());
        updateWrapper.eq(CourseRecord::getCoursePubId, dto.getCourseRecordId());
        boolean result = this.update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(LearningErrorCode.E_202204);
        }
        return dto;
    }

    private CourseRecordDTO create(CourseRecordDTO dto, CoursePubIndexDTO coursePubIndexDTO) {
        CourseRecord record = CourseRecordConvert.INSTANCE.dto2entity(dto);
        //获取课程的课程大纲
        String teachplanJson = coursePubIndexDTO.getTeachplan();
        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplanJson, TeachplanDTO.class);
        if (ObjectUtils.isEmpty(teachplanDTO)) {
            ExceptionCast.cast(LearningErrorCode.E_202204);
        }
        // 3.2.2 获得二级课程计划第一个章节内容

        List<TeachplanDTO> secTeachPlanTreeNodes = teachplanDTO.getTeachPlanTreeNodes();
        if (CollectionUtils.isEmpty(secTeachPlanTreeNodes)) {
            ExceptionCast.cast(LearningErrorCode.E_202205);
        }

        TeachplanDTO secTeachplan = secTeachPlanTreeNodes.get(0);

        // 3.2.2 获得三级课程计划第一个小节内容
        List<TeachplanDTO> thridTeachPlanTreeNodes = secTeachplan.getTeachPlanTreeNodes();
        if (CollectionUtils.isEmpty(thridTeachPlanTreeNodes)) {
            ExceptionCast.cast(LearningErrorCode.E_202205);
        }
        //获取三级节点
        TeachplanDTO thirdTeachplan = thridTeachPlanTreeNodes.get(0);

        //课程机构id
        record.setCompanyId(coursePubIndexDTO.getCompanyId());
        //课程id
        record.setCourseId(coursePubIndexDTO.getCourseId());
        //课程发布ID
        record.setCoursePubId(coursePubIndexDTO.getIndexId());
        //课程名称
        record.setCoursePubName(coursePubIndexDTO.getName());
        //教育模式
        record.setTeachmode(coursePubIndexDTO.getTeachmode());
        //设置正在学习的课程计划章节Id
        record.setTeachplanId(thirdTeachplan.getTeachPlanId());
        //正在学习的课程计划章节名称
        record.setTeachplanName(thirdTeachplan.getPname());
        //是否已经支付
        record.setPaid(CommonEnum.USING_FLAG.getCodeInt());

        boolean result = this.save(record);
        if (!result) {
            ExceptionCast.cast(LearningErrorCode.E_202204);
        }
        CourseRecordDTO courseRecordDTO = CourseRecordConvert.INSTANCE.entity2dto(record);
        return courseRecordDTO;
    }


    /**
     * 根据课程发布Id、课程计划Id、媒资信息Id、用户名获得视频播放信息
     *
     * @param coursePubId
     * @param teachplanId
     * @param mediaId
     * @param username
     * @return
     */
    @Override
    public ResourceUrlModel playUrl(Long coursePubId, Long teachplanId, Long mediaId, String username) {
        // 创建一个结果对象
        ResourceUrlModel resourceUrlModel = new ResourceUrlModel();


        // 1.判断关键数据
        // Long coursePubId, Long mediaId, Long teachplanId
        if (ObjectUtils.isEmpty(coursePubId) ||
                ObjectUtils.isEmpty(mediaId)||
                ObjectUtils.isEmpty(teachplanId)
        ) {
            resourceUrlModel.wrong(CommonErrorCode.E_100101);
            return resourceUrlModel;
        }

        // 2.判断业务数据
        // 2.1 根据课程发布数据id获得CoursePubIndexDTO：判断是否存在
        RestResponse<CoursePubIndexDTO> restResponse = searchApiAgent.getCoursePubIndexById4s(coursePubId);

        if (!(restResponse.isSuccessful())) {
            resourceUrlModel.wrong(LearningErrorCode.E_202202);
            return resourceUrlModel;
        }

        CoursePubIndexDTO coursePubIndexDTO = restResponse.getResult();

        if (ObjectUtils.isEmpty(coursePubIndexDTO)) {
            resourceUrlModel.wrong(LearningErrorCode.E_202202);
            return resourceUrlModel;
        }

        // 2.2 根据课程计划的id来判断课程计划是否存在
        String teachplanJsonString = coursePubIndexDTO.getTeachplan();

        // 课程大纲的树形结构（三级课程计划），获得数据为一级课程计划数据
        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplanJsonString, TeachplanDTO.class);

        // 获得二级课程计划集合数据
        List<TeachplanDTO> secTeachPlanTreeNodes = teachplanDTO.getTeachPlanTreeNodes();
        if (CollectionUtils.isEmpty(secTeachPlanTreeNodes)) {
            resourceUrlModel.wrong(LearningErrorCode.E_202205);
            return resourceUrlModel;
        }

        // 声明一个三级课程计划的变量
        TeachplanDTO thirdTeachplanDTO = null;


        for (TeachplanDTO secTeachPlanTreeNode : secTeachPlanTreeNodes) {

            if (!(ObjectUtils.isEmpty(thirdTeachplanDTO))) {
                break;
            }

            // 获得二级中的三级课程计划集合数据
            List<TeachplanDTO> thirdTeachPlanTreeNodes = secTeachPlanTreeNode.getTeachPlanTreeNodes();

            // 有些课程的课程计划是只有二级课程计划（原因为了课程的营销）
            if (CollectionUtils.isEmpty(thirdTeachPlanTreeNodes)) {
                continue;
            }


            // 从三级课程计划查找用户所选择的teachplanid值的内容
            for (TeachplanDTO thirdTeachPlanTreeNode : thirdTeachPlanTreeNodes) {

                if (ObjectUtils.nullSafeEquals(teachplanId, thirdTeachPlanTreeNode.getTeachPlanId())) {
                    thirdTeachplanDTO = thirdTeachPlanTreeNode;
                    break;
                }
            }

        }

        if (ObjectUtils.isEmpty(thirdTeachplanDTO)) {
            resourceUrlModel.wrong(LearningErrorCode.E_202206);
            return resourceUrlModel;
        }


        // 3.根据课程的charge来判断是否有权限获得资源路径地址

        Boolean is_paid = false;

        String charge = coursePubIndexDTO.getCharge();

        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            // 如果课程是收费
            //  ---> 如果该课程计划是免费返回资源地址
            // 课程计划：isPreview = 1--免费 ， isPreview = 0--收费
            String isPreview = thirdTeachplanDTO.getIsPreview();
            if (CommonEnum.USING_FLAG.getCode().equals(isPreview)) {
                is_paid = true;
            }

            //  ---> 根据学习记录CourseRecord：paid=1
            if (!is_paid) {

                // 查看一个人对一门收费课程是否有购买记录：username，coursePubId
                LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();

                queryWrapper.eq(CourseRecord::getUserName, username);
                queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);

                CourseRecord courseRecord = this.getOne(queryWrapper);
                if (!(ObjectUtils.isEmpty(courseRecord))) {

                    if (CourseRecord.IS_PAID.equals(courseRecord.getPaid())) {
                        is_paid = true;
                    }
                }
            }

        } else {
            //         如果课程是免费---> 返回资源路径地址
            is_paid = true;
        }



        // 4.根据媒资id获得媒资信息资源数据ResourceURLModel：判断数据是否存在
        if (is_paid) {

            RestResponse<ResourceUrlModel> response = mediaApiAgent.playUrl(mediaId);

            if (!(response.isSuccessful())) {
                resourceUrlModel.wrong(LearningErrorCode.E_200101);
                return resourceUrlModel;
            }

            ResourceUrlModel result = response.getResult();
            return result;
        }

        // 返回没有找到媒资信息的内容
        resourceUrlModel.wrong(LearningErrorCode.E_202207);
        return resourceUrlModel;
    }
}
